#include "GfxDriver/WGL/WGLVertexBuffer.h"
#include "GfxDriver/GfxDriver.h"

#include "Core/LogService.h"

namespace Orca {

	//--------------------------------------------------------------------------
	WGLVertexBuffer* WGLVertexBuffer::create(
		GfxDriver *gfxDriver,
		uint32 sizeInBytes,
		bool staticUsage) {

		WGLVertexBuffer *vb = new WGLVertexBuffer;

		if( !vb->_init(gfxDriver, sizeInBytes, staticUsage) ) {

			delete vb;
			return NULL;
		}

		LOG_MSG(
			"WGLGfxDriver: Vertex Buffer with " + toStr(sizeInBytes) + " bytes created;"
			"glHandle=" + toStr((uint32)vb->mGLHandle) );

		return vb;
	}

	//--------------------------------------------------------------------------
	bool WGLVertexBuffer::_init(
		GfxDriver *gfxDriver,
		uint32 sizeInBytes,
		bool staticUsage) {

		mGfxDriver = gfxDriver;
		mSizeInBytes = sizeInBytes;

		mGfxDriver->resetErrors();

		if(staticUsage)
			mGLUsage = GL_STATIC_DRAW;
		else
			mGLUsage = GL_DYNAMIC_DRAW;

		glGenBuffers(1, &mGLHandle);

		glBindBuffer(GL_ARRAY_BUFFER, mGLHandle);
		glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)mSizeInBytes, NULL, mGLUsage);
		glBindBuffer(GL_ARRAY_BUFFER, 0);

		if( GL_NO_ERROR != glGetError() ) {

			LOG_ERR(
				"WGLGfxDriver: Failed to create vertex buffer\n"
				"\tReason: glBufferData failed" );

			return false;
		}

		return true;
	}

	//--------------------------------------------------------------------------
	WGLVertexBuffer::WGLVertexBuffer()
		: mGfxDriver(NULL)
		, mSizeInBytes(0)
		, mGLHandle(0)
		, mGLUsage(0) {

	}

	//--------------------------------------------------------------------------
	WGLVertexBuffer::~WGLVertexBuffer() {

		if(mGLHandle)
			glDeleteBuffers(1, &mGLHandle);
	}

	//--------------------------------------------------------------------------
	uint32 WGLVertexBuffer::getSizeInBytes() {
		return mSizeInBytes;
	}

	//--------------------------------------------------------------------------
	unsigned int WGLVertexBuffer::getAPIHandle() {
		return mGLHandle;
	}

	//--------------------------------------------------------------------------
	uint8* WGLVertexBuffer::requestUpload(bool discardCurrent) {

		glBindBuffer(GL_ARRAY_BUFFER, mGLHandle);

		if(discardCurrent)
			glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)mSizeInBytes, NULL, mGLUsage);

		return (uint8*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
	}
	
	//--------------------------------------------------------------------------
	void WGLVertexBuffer::uploadToGPU() {

		glBindBuffer(GL_ARRAY_BUFFER, mGLHandle);
		glUnmapBuffer(GL_ARRAY_BUFFER);

		glBindBuffer(GL_ARRAY_BUFFER, 0);
	}

	//--------------------------------------------------------------------------
}